import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:provide/provide.dart';
import 'package:qgchat/common/class/date/index.dart';
import 'package:qgchat/common/class/websocket/videoWs.dart';
import 'package:qgchat/common/global/global.dart';
import 'package:qgchat/http/apis/user.dart';
import 'package:qgchat/http/models/TextureModel.dart';
import 'package:qgchat/http/models/UserGetAnchorWechatModel.dart';
import 'package:qgchat/http/models/tokenuserInfoModel.dart';
import 'package:qgchat/http/models/wsAllGiftModel.dart';
import 'package:qgchat/page/live/videoPage/anchorGiftBox.dart';
import 'package:qgchat/page/live/videoPage/giftBox.dart';
import 'package:qgchat/states/states_model/user.dart';
import 'package:qgchat/widgets/Zego/ZegoFace.dart';
import 'package:qgchat/widgets/Zego/ZegoPreview.dart';
import 'package:zego_express_engine/zego_express_engine.dart';
import 'package:zego_faceunity_plugin/zego_faceunity_plugin.dart';

import 'Bloc/TargetInfoBlocBloc.dart';

class Talk extends StatefulWidget {
  final int inv;
  final String targetToken;
  Talk({@required this.inv, @required this.targetToken, Key key})
      : super(key: key);

  @override
  _TalkState createState() => _TalkState();
}

class _TalkState extends State<Talk> {
  // 计费socket
  VideoWs socket = VideoWs();

  // 订阅结束通话
  StreamSubscription stoptalkSub;

  // 监听关闭本地摄像头
  ValueNotifier<bool> cameraNot = ValueNotifier<bool>(true);

  // 当前显示小窗
  bool showSmall = true;

  @override
  void initState() {
    super.initState();
    final not = Global.socketNot;

    // socket - 通话结束
    stoptalkSub = not.value
        .map((str) => jsonDecode(str))
        .where((cls) => cls['datatype'] == 'stoptalk')
        .listen(
      (res) {
        toast('对方结束了视频通话');
        socket.dispose();
        goPage(
          context,
          '/endCall',
          param: {
            "token": widget.targetToken,
            "inv": widget.inv,
          },
          replace: true,
        );
      },
    );

    // 监听关闭本地摄像头
    cameraNot.addListener(() {
      setState(() {
        showSmall = cameraNot.value;
      });
    });
  }

  @override
  void dispose() {
    // 修改通话状态
    Global.talking.value = false;

    // 销毁通话结束socket监听
    stoptalkSub?.cancel();

    ZegoExpressEngine.onRemoteCameraStateUpdate = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 计算屏幕像素
    final width = MediaQuery.of(context).size.width.toInt();
    final height = MediaQuery.of(context).size.height.toInt();
    final ratio = MediaQuery.of(context).devicePixelRatio.toInt();
    final screenWidthPx = width * ratio;
    final screenHeightPx = height * ratio;

    // 确定主播大屏 用户小屏
    ViewWidget window;
    final user = Provide.value<UserState>(context).info;
    final iAmAnchor = user.memberType == 1;
    if (iAmAnchor) {
      window = ViewWidget(
        big: ZegoPreview(
          screenWidthPx: screenWidthPx,
          screenHeightPx: screenHeightPx,
        ),
        small: _StreamView(
          screenWidthPx: px(492).toInt(),
          screenHeightPx: px(654).toInt(),
        ),
      );
    } else {
      window = ViewWidget(
        small: ZegoPreview(
          screenWidthPx: px(492).toInt(),
          screenHeightPx: px(654).toInt(),
        ),
        big: _StreamView(
          screenWidthPx: screenWidthPx,
          screenHeightPx: screenHeightPx,
        ),
      );
    }

    return BlocProvider<TargetInfoBlocBloc>(
      create: (context) => TargetInfoBlocBloc(
        inv: widget.inv,
        targetToken: widget.targetToken,
      ),
      child: WillPopScope(
        onWillPop: () async => false,
        child: _ZegoInit(
          child: _Charging(
            socket: socket,
            inv: widget.inv,
            targetToken: widget.targetToken,
            child: Scaffold(
              backgroundColor: Colors.grey,
              body: Stack(
                children: [
                  window.big,
                  if (showSmall) _SmallWindow(child: window.small),
                  _Time(),
                  _Intimacy(token: widget.targetToken),
                  _UserInfo(),
                  _ToolPanel(
                    socket: socket,
                    cameraNot: cameraNot,
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

// 计费socket
class _Charging extends StatefulWidget {
  final VideoWs socket;
  final Widget child;
  final int inv;
  final String targetToken;
  _Charging({
    @required this.socket,
    @required this.child,
    @required this.inv,
    @required this.targetToken,
    Key key,
  }) : super(key: key);

  @override
  __ChargingState createState() => __ChargingState();
}

class __ChargingState extends State<_Charging> {
  @override
  void initState() {
    super.initState();
    final not = widget.socket.streamNotifier;
    not.addListener(() {
      if (not.value == null) return;
      not.value
          .map((str) => jsonDecode(str))
          .where((map) => map['datatype'] == 'nomoney')
          .listen(
        (res) {
          // if (res['msg'] == '您的余额已不足通话两分钟') {
          //   toast(res['msg']);
          // }
          if (res['msg'] == '您的余额已不足继续通话') {
            widget.socket.dispose();
            Global.ws.stoptalk(
              widget.targetToken,
              msg: "对方费用不足，系统结束通话",
            );
            goPage(
              context,
              '/endCall',
              param: {
                "token": widget.targetToken,
                "inv": widget.inv,
              },
              replace: true,
            );
          }
        },
      );
    });

    widget.socket.start(widget.targetToken, widget.inv);
  }

  @override
  Widget build(BuildContext context) => widget.child;
}

// 即构初始化
class _ZegoInit extends StatefulWidget {
  final Widget child;
  _ZegoInit({@required this.child, Key key}) : super(key: key);

  @override
  __ZegoInitState createState() => __ZegoInitState();
}

class __ZegoInitState extends State<_ZegoInit> {
  String roomID;

  @override
  void initState() {
    super.initState();

    // 前置摄像头
    ZegoExpressEngine.instance.useFrontCamera(true);
    // 默认关闭摄像头
    ZegoExpressEngine.instance.enableCamera(true);

    // 监听用户信息获取完成
    context.bloc<TargetInfoBlocBloc>().listen((info) {
      if (info.id == null) return;

      // 确定房间id为
      // inv-主播id-用户id
      final inv = context.bloc<TargetInfoBlocBloc>().inv;
      final user = Provide.value<UserState>(context).info;
      final iAmAnchor = user.memberType == 1;
      if (iAmAnchor) {
        roomID = "call-$inv-${user.id}-${info.id}";
      } else {
        roomID = "call-$inv-${info.id}-${user.id}";
      }

      // 创建用户对象
      ZegoUser uid = ZegoUser.id('${user.id}');
      // 开始登陆房间
      ZegoExpressEngine.instance.loginRoom(roomID, uid);
      // 开始推流
      ZegoExpressEngine.instance.startPublishingStream('${user.id}');
    });
  }

  @override
  void dispose() {
    // 开启摄像头
    ZegoExpressEngine.instance.enableCamera(true);
    // 停止推流
    ZegoExpressEngine.instance.stopPublishingStream();
    // 登出房间
    ZegoExpressEngine.instance.logoutRoom(roomID);

    super.dispose();
  }

  @override
  Widget build(BuildContext context) => widget.child;
}

// 对方的界面
class _StreamView extends StatefulWidget {
  final int screenWidthPx;
  final int screenHeightPx;

  _StreamView({
    @required this.screenWidthPx,
    @required this.screenHeightPx,
    Key key,
  }) : super(key: key);

  @override
  __StreamViewState createState() => __StreamViewState();
}

class __StreamViewState extends State<_StreamView> {
  final Map<String, TextureModel> textures = {};
  TextureModel streamView;
  bool get isInit => streamView != null;

  // 当前显示小窗
  bool showSmall = true;

  @override
  void initState() {
    super.initState();
    // 监听房间内流数量变更的通知
    ZegoExpressEngine.onRoomStreamUpdate = (
      String roomID,
      ZegoUpdateType updateType,
      List<ZegoStream> streamList,
      Map<String, dynamic> extendedData,
    ) async {
      // 房间内新增主播
      if (updateType == ZegoUpdateType.Add) {
        // 创建并储存用户信息
        for (var stream in streamList) {
          final texture = await createTextureRenderer();
          final model = TextureModel.fromJson(texture);
          textures[stream.streamID] = model;
          // 开始拉流
          ZegoExpressEngine.instance.startPlayingStream(
            stream.streamID,
            canvas: model.canvas,
          );
          streamView = model;
        }
        setState(() {});
      }
      // 房间内减少主播
      else if (updateType == ZegoUpdateType.Delete) {
        for (var stream in streamList) {
          final texture = textures[stream.streamID];
          // 停止播放流
          ZegoExpressEngine.instance.stopPlayingStream(stream.streamID);
          // 销毁
          ZegoExpressEngine.instance.destroyTextureRenderer(texture.textureID);
          // 删除保存的信息
          textures.remove(stream.streamID);
          streamView = null;
        }
        setState(() {});
      }
    };
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final user = Provide.value<UserState>(context).info;
    if (user.memberType == 1) {
      // 主播监听用户摄像头
      ZegoExpressEngine.onRemoteCameraStateUpdate = (
        String streamID,
        ZegoRemoteDeviceState state,
      ) {
        if (state == ZegoRemoteDeviceState.Open) {
          showSmall = true;
        } else if (state == ZegoRemoteDeviceState.Disable) {
          showSmall = false;
        }
        setState(() {});
      };
    }
  }

  @override
  void dispose() {
    textures.forEach((key, value) {
      // 停止播放流
      ZegoExpressEngine.instance.stopPlayingStream(key);
    });
    // 销毁
    if (isInit) {
      ZegoExpressEngine.instance.destroyTextureRenderer(streamView.textureID);
    }
    super.dispose();
  }

  // 创建外接纹理
  createTextureRenderer() async {
    final textureID = await ZegoExpressEngine.instance.createTextureRenderer(
      widget.screenWidthPx,
      widget.screenHeightPx,
    );
    final view = Texture(textureId: textureID);
    final canvas = ZegoCanvas.view(textureID);
    canvas.viewMode = ZegoViewMode.AspectFill;
    return {
      "textureID": textureID,
      "widget": view,
      "canvas": canvas,
    };
  }

  @override
  Widget build(BuildContext context) {
    return isInit && showSmall ? streamView.widget : Container();
  }
}

class _UserInfo extends StatelessWidget {
  const _UserInfo({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final top = MediaQuery.of(context).padding.top;
    return BlocBuilder<TargetInfoBlocBloc, TokenuserInfoModel>(
      builder: (context, state) {
        if (state.id == null) return Container();

        return Positioned(
          top: top + px(30),
          left: px(30),
          child: Container(
            height: px(60),
            decoration: BoxDecoration(
              color: Colors.black.withOpacity(.3),
              borderRadius: BorderRadius.circular(px(30)),
            ),
            child: Stack(
              overflow: Overflow.visible,
              alignment: Alignment.centerLeft,
              children: [
                Row(
                  children: [
                    Container(
                      margin: EdgeInsets.only(left: px(90)),
                      padding: EdgeInsets.only(right: px(30)),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            state.memberNickname,
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: px(26),
                            ),
                          ),
                          Text(
                            "id: ${state.id}",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: px(20),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
                Positioned(
                  left: 0,
                  child: Container(
                    width: px(70),
                    height: px(70),
                    padding: EdgeInsets.all(px(3)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(px(35)),
                    ),
                    child: CircleAvatar(
                      backgroundImage: NetworkImage(state.memberHead),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

// 视频小窗
class _SmallWindow extends StatefulWidget {
  final Widget child;
  _SmallWindow({@required this.child, Key key}) : super(key: key);

  @override
  __SmallWindowState createState() => __SmallWindowState();
}

class __SmallWindowState extends State<_SmallWindow> {
  @override
  Widget build(BuildContext context) {
    final top = MediaQuery.of(context).padding.top;

    return Positioned(
      top: top + px(30),
      right: px(30),
      child: Container(
        width: px(246),
        height: px(327),
        child: widget.child,
      ),
    );
  }
}

// 工具栏
class _ToolPanel extends StatefulWidget {
  final VideoWs socket;
  final ValueNotifier<bool> cameraNot;
  _ToolPanel({this.socket, this.cameraNot, Key key}) : super(key: key);

  @override
  __ToolPanelState createState() => __ToolPanelState();
}

class __ToolPanelState extends State<_ToolPanel> {
  // 当前是否前置摄像头
  bool isFront = true;

  // 当前是否开启摄像头
  bool enableCamera = false;

  @override
  Widget build(BuildContext context) {
    final user = Provide.value<UserState>(context).info;
    return Positioned(
      bottom: px(150),
      right: px(30),
      child: Column(
        children: [
          Container(
            width: px(84),
            padding: EdgeInsets.symmetric(vertical: px(44)),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(px(42)),
              color: Colors.black.withOpacity(.3),
            ),
            child: Column(
              children: [
                GestureDetector(
                  onTap: () {
                    final token =
                        context.bloc<TargetInfoBlocBloc>().targetToken;
                    final user = Provide.value<UserState>(context).info;
                    final shape = RoundedRectangleBorder(
                      borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(px(24)),
                        topRight: Radius.circular(px(24)),
                      ),
                    );

                    if (user.memberType == 1) {
                      showModalBottomSheet(
                        context: context,
                        shape: shape,
                        builder: (BuildContext context) {
                          return AnchorGiftBox(token: token);
                        },
                      );
                    } else {
                      showModalBottomSheet(
                        context: context,
                        shape: shape,
                        builder: (BuildContext context) {
                          return GiftBox(
                            token: token,
                            canShowSvga: true,
                          );
                        },
                      );
                    }
                  },
                  child: _ToolPanelBtn(
                    icon: 'gift_white',
                    text: '礼物',
                  ),
                ),
                if (user.memberType == 1)
                  Container(
                    margin: EdgeInsets.only(top: px(44)),
                    child: GestureDetector(
                      onTap: () {
                        ZegoFace.instance.show(context);
                      },
                      child: _ToolPanelBtn(
                        icon: 'beauty',
                        text: '美颜',
                      ),
                    ),
                  ),
                if (user.memberType == 0)
                  Container(
                    margin: EdgeInsets.only(top: px(44)),
                    child: GestureDetector(
                      onTap: () {
                        enableCamera = !enableCamera;
                        ZegoExpressEngine.instance.enableCamera(enableCamera);
                        widget.cameraNot.value = enableCamera;
                      },
                      child: _ToolPanelBtn(
                        icon: 'close_camera',
                        text: '开关',
                      ),
                    ),
                  ),
                SizedBox(height: px(44)),
                GestureDetector(
                  onTap: () {
                    isFront = !isFront;
                    ZegoFaceunityPlugin.instance.switchCamera(isFront
                        ? ZegoCameraPosition.Front
                        : ZegoCameraPosition.Back);
                  },
                  child: _ToolPanelBtn(
                    icon: 'change_camera',
                    text: '切换',
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: px(30)),
          GestureDetector(
            onTap: () {
              final inv = context.bloc<TargetInfoBlocBloc>().inv;
              final token = context.bloc<TargetInfoBlocBloc>().targetToken;
              widget.socket.dispose();
              Global.ws.stoptalk(token, msg: "对方结束了通话");
              goPage(
                context,
                '/endCall',
                param: {"token": token, "inv": inv},
                replace: true,
              );
            },
            child: Container(
              width: px(70),
              height: px(70),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(px(35)),
                color: Colors.black.withOpacity(.3),
              ),
              child: Icon(
                Icons.close,
                color: Colors.white,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// 可操作工具栏
class _ToolPanelBtn extends StatelessWidget {
  final String icon;
  final String text;
  const _ToolPanelBtn({
    @required this.icon,
    @required this.text,
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child: Column(
        children: [
          Image.asset(
            "assets/images/icon/$icon.png",
            width: px(40),
            height: px(40),
            fit: BoxFit.contain,
          ),
          SizedBox(height: px(7)),
          Text(
            text,
            style: TextStyle(
              color: Colors.white,
              fontSize: px(20),
            ),
          ),
        ],
      ),
    );
  }
}

// 计时组件
class _Time extends StatefulWidget {
  _Time({Key key}) : super(key: key);

  @override
  __TimeState createState() => __TimeState();
}

class __TimeState extends State<_Time> {
  final int start = DateTime.now().millisecondsSinceEpoch;
  String date = "00:00:00";
  Timer timer;

  @override
  void initState() {
    super.initState();
    timer = Timer.periodic(
      Duration(seconds: 1),
      (timer) {
        final now = DateTime.now().millisecondsSinceEpoch;
        date = Date.difference(start, now);
        setState(() {});
      },
    );
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final top = MediaQuery.of(context).padding.top;
    return Positioned(
      top: top + px(120),
      left: px(30),
      child: Container(
        width: px(150),
        height: px(50),
        decoration: BoxDecoration(
          color: Colors.black.withOpacity(.3),
          borderRadius: BorderRadius.circular(px(25)),
        ),
        child: Center(
          child: Text(
            date,
            style: TextStyle(
              color: Colors.white,
              fontSize: px(26),
            ),
          ),
        ),
      ),
    );
  }
}

// 大小窗模型
class ViewWidget {
  final Widget big;
  final Widget small;
  ViewWidget({this.big, this.small});
}

// 亲密度
class _Intimacy extends StatefulWidget {
  final String token;

  _Intimacy({@required this.token, Key key}) : super(key: key);

  @override
  __IntimacyState createState() => __IntimacyState();
}

class __IntimacyState extends State<_Intimacy> {
  final circular = Path()
    ..moveTo(55, 15)
    ..cubicTo(55, 12, 50, 0, 30, 0)
    ..cubicTo(0, 0, 0, 37.5, 0, 37.5)
    ..cubicTo(0, 55, 20, 77, 55, 95)
    ..cubicTo(90, 77, 110, 55, 110, 37.5)
    ..cubicTo(110, 37.5, 110, 0, 80, 0)
    ..cubicTo(65, 0, 55, 12, 55, 15)
    ..close();

  UserGetAnchorWechatModel info;

  bool isUpIntimacy = false;

  Timer timer;

  int upGold = 0;

  // 分钟计时
  int timeCount = 0;

  @override
  void initState() {
    super.initState();
    // 每1min跳一次
    timer = Timer.periodic(
      Duration(minutes: 1),
      (timer) {
        timeCount++;
        upGold = info?.timePrice ?? 0;
        isUpIntimacy = true;
        setState(() {});
        io();
        Timer(
          Duration(seconds: 3),
          () {
            isUpIntimacy = false;
            setState(() {});
          },
        );
      },
    );

    // socket监听赠送的礼物
    final not = Global.socketNot;
    if (not.value != null) {
      not.value
          .map((str) => jsonDecode(str))
          .where((cls) => cls['datatype'] == 'allgift')
          .map((cls) => WsAllGiftModel.fromJson(cls['data']))
          .where((cls) {
        UserState user = state(context, 'user');
        final isAnchor = user.info?.memberType == 1;
        String ut = isAnchor ? widget.token : user.info.memberToken;
        String at = !isAnchor ? widget.token : user.info.memberToken;
        return cls.anchorToken == at && ut == cls.token;
      }).listen(
        (res) {
          UserApis.giftInfo(res.id).then((req) {
            if (req == null) return;
            upGold = res.number * req['gift_gold'];
            isUpIntimacy = true;
            setState(() {});
            io();
            Timer(
              Duration(seconds: 3),
              () {
                isUpIntimacy = false;
                setState(() {});
              },
            );
          });
        },
      );
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    io();
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  io() {
    UserState user = state(context, 'user');
    final isAnchor = user.info?.memberType == 1;
    String ut = isAnchor ? widget.token : user.info.memberToken;
    String at = !isAnchor ? widget.token : user.info.memberToken;
    UserApis.userGetAnchorWechat(ut, at).then((res) {
      if (res == null) return;
      info = UserGetAnchorWechatModel.fromJson(res);
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    double value = 0;
    final intimacy = (info?.spend ?? 0) + timeCount * (info?.timePrice ?? 0);
    final need = info?.require ?? 0;
    if (info != null) {
      // 主播未开放微信
      if (info.open == 0 || info.wxaccount == null) {
        return SizedBox.shrink();
      }

      if (intimacy > need) {
        value = 1;
      } else {
        value = intimacy / need;
      }
    }

    final top = MediaQuery.of(context).padding.top;
    return Positioned(
      left: px(30),
      top: top + px(240),
      child: Stack(
        overflow: Overflow.visible,
        children: [
          Transform.scale(
            scale: .3,
            alignment: Alignment.topLeft,
            child: Column(
              children: [
                LiquidCustomProgressIndicator(
                  value: value,
                  valueColor: AlwaysStoppedAnimation(
                    value == 1 ? Colors.red : Colors.pink,
                  ),
                  backgroundColor: Colors.pink[50],
                  direction: Axis.vertical,
                  shapePath: circular,
                ),
                SizedBox(height: px(30)),
                Text(
                  value == 1 ? '亲密度已满' : '$intimacy/$need',
                  style: TextStyle(
                    fontSize: px(100),
                    color: Colors.white,
                    shadows: [
                      Shadow(
                        color: Colors.black,
                        blurRadius: 1,
                        offset: Offset(1, 1),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
          if (isUpIntimacy)
            Positioned(
              top: -px(50),
              left: px(30),
              child: Text(
                '+$upGold',
                style: TextStyle(
                  fontSize: px(32),
                  color: Colors.white,
                  shadows: [
                    Shadow(
                      color: Colors.black,
                      blurRadius: 1,
                      offset: Offset(1, 1),
                    ),
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }
}
